package ru.dmitry;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author dmitry
 */

import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;

public class ConnectionClient {

	static final int REMOTE_PORT = 18256;
	static final String HELLO_STRING = "Hello world!";
	static final int BUFFER_LENGTH = 1024;	//Length of buffer to send and receive files
	public static final int MAGICWORD_CHAR_LENGTH = 20;
	Socket commandSocket = null;			//Socket for commands and control infomation transmission
	Socket dataSocket = null;				//Socket for data transmission
	Scanner responseChannel = null;			//Channel for server responses reading
	DataOutputStream commandChannel = null;	//Channel for commands sending
	InputStream inData;
	OutputStream outData;

	static {
		loadProperties();
	}

	public ConnectionClient() {
	}

	/**
	 * The method processes user commands.
	 */
	public void processUserCommands() {
		Scanner userInput, command;
		userInput = new Scanner(System.in);
		String word, line;

		while(true) {
			System.out.print("\n>");
			try{
				line = userInput.nextLine();
				if(line.isEmpty())
					continue;
				command = new Scanner(line);
			}catch(Exception ex) {
				System.err.println("Creating command Scanner:\n"+ex);
				break;
			}

			word = command.next();
			if(word.equals("open")) {
				if(commandSocket != null)
					System.out.println("You have to close the current conection before\n");
				else {
					try {
						open(command, userInput);
					}
					catch(IncorrectUsageException e) {
					}
					catch(Exception e) {
						System.err.println("Some problems:"+e);
						e.printStackTrace();
					}
					if(commandSocket != null)
						System.out.println("Connection established...");
				}
			}
			else if(word.equals("help")) {
				help(command);
			}
			else if(word.equals("ls")) {
				ls();
			}
			else if(word.equals("put")) {
				put(command);
			}
			else if(word.equals("get")) {
				get(command);
			}
			else if(word.equals("set")) {
				set(command, userInput);
			}
			else if(word.equals("close")) {
				close();
			}
			else if(word.equals("quit")) {
				quit();
				break;
			}
			else {
				System.out.println("Unknown command. Print help for help");
			}
		}
	}

	/**
	 * The method loads properties of the client application from file.
	 */
	private static void loadProperties() {
		System.setProperty("javax.net.ssl.trustStore", "mySrvKeystore");
		System.setProperty("javax.net.ssl.keyStorePassword", "123456");
	}

	/**
	 * @param command - Scanner that contains arguments
	 * @param userInput - Scanner that contains user input
	 * Connects to remote server and logs in or registers.
	 */
	private void open(Scanner command, Scanner userInput) throws IncorrectUsageException {
		String remoteHost, login, password;
		if(command.hasNext())
			remoteHost = command.next();
		else {
			throw new IncorrectUsageException();
		}
		System.out.print("Login:");
		if(userInput.hasNext())
			login = userInput.next();
		else
			throw new IncorrectUsageException("End of input.");
		System.out.print("Password:");
		if(userInput.hasNext())
			password = userInput.next();	//This line MUST be replaced with some sophisticated masking!!!
		else
			throw new IncorrectUsageException("End of input.");

		SocketFactory socketFactory = SSLSocketFactory.getDefault();
		String response;
		String magicWord;		//A string that server sends to client expecting to receive
								//it when client creates a connection for data transmission
		int dataPort;

		try {
			commandSocket = socketFactory.createSocket(remoteHost, REMOTE_PORT);
			commandChannel = new DataOutputStream(commandSocket.getOutputStream());
			responseChannel = new Scanner(commandSocket.getInputStream());
			commandChannel.writeBytes(HELLO_STRING+"\n"+login+"\n"+password+"\n");
			if(responseChannel.hasNext()) {
				response = responseChannel.nextLine();
				if(!response.equals(HELLO_STRING)) {
					System.out.println("Remote host refused to establish connection\n"+response);
					commandSocket = null;
					return;
				}
				else {

					if(responseChannel.hasNext()) {
						magicWord = responseChannel.next();
						System.out.println("Magic word:"+magicWord);
					}
					else {
						System.out.println("Cannot connect to remote host\n");
						commandSocket = null;
						return;
					}
					if(responseChannel.hasNext()) {
						String s = "";
						try {
							dataPort = Integer.parseInt(s = responseChannel.next());
						}catch(NumberFormatException ex) {
							System.err.println(s);
							throw ex;
						}
					}
					else {
						System.out.println("Cannot connect to remote host\n");
						commandSocket = null;
						return;
					}
				}
			}
			else {
				System.out.println("Cannot connect to remote host\n");
				commandSocket = null;
				return;
			}
			dataSocket = socketFactory.createSocket(remoteHost, dataPort);
			inData = dataSocket.getInputStream();
			outData = dataSocket.getOutputStream();
			outData.write(magicWord.getBytes());
		}
		catch(UnknownHostException e) {
			System.out.println("Unknown host");
			commandSocket = null;
			return;
		}
		catch(IOException e) {
			System.out.println("Cannot connect to remote host\n" + e);
			commandSocket = null;
			return;
		}


	}

	/**
	 * @param command - Scanner that contains arguments of open
	 * Prints help
	 */
	private void help(Scanner command) {
	}

	/**
	 * Lists directory contents
	 */
	private void ls() {
	}

	/**
	 * @param command - Scanner that contains arguments of put
	 * Uploads file to server
	 */
	private void put(Scanner command) {
		String filePath;
		long size;
		int len;
		byte[] buffer = new byte[BUFFER_LENGTH];
		
		try {
			filePath = command.next();
			File file = new File(filePath);
			if(!file.exists()) {
				System.out.println(filePath+" does not exist.");
				return;
			}
			if(!file.isFile()) {
				System.out.println(filePath+" is not a normal file.");
				return;
			}
			size = file.length();
			commandChannel.writeBytes("put "+file.getName()+" "+size+"\n");
			FileInputStream fr = new FileInputStream(file);
			while( (len = fr.read(buffer)) != -1)
				outData.write(buffer, 0, len);
			fr.close();
		}catch(NoSuchElementException e) {
			System.err.println("No file is specified.");
			return;
		}catch(IOException e) {
			System.err.println("Failed to send file.");
		}
	}

	/**
	 * @param command - Scanner that contains arguments of get
	 * Downloads file from server
	 */
	private void get(Scanner command) {
	}

	/**
	 *
	 * @param command - Scanner that contains arguments of set
	 * @param UserInput - Scanner that contains user input
	 * Sets properties of client application.
	 */
	private void set(Scanner command, Scanner userInput) {
	}

	/**
	 * Logs out and closes connection
	 */
	private void close() {
		if(commandSocket == null)
			System.out.println("No connection established.");
		else {
			try {
				inData.close();
				outData.close();
				commandChannel.close();
				responseChannel.close();
				commandSocket.close();
			} catch (IOException ex) {
				System.out.println("Problems occured trying to close connection.");
			}
			commandSocket = null;
			dataSocket = null;
			System.out.println("Connection closed.");
		}
	}

	/**
	 * Causes the application to exit
	 */
	private void quit() {
	}
}
